﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Microsoft.SharePoint;
using System.Text.RegularExpressions;

namespace LizardSoft.Common.FlexibleStructureDeployment
{
    public static partial class StructureHelper
    {
        private static void DeleteContentTypeFields(SPWeb web, string listFolderUrl, SPContentTypeId listContentTypeId, Func<string, bool> applyFilter)
        {
            SPList list = GetSPListFromFolderUrl(web, listFolderUrl);
            SPContentType listContentType = list.ContentTypes[listContentTypeId];
            
            // получаем набор названий полей, использующихся в типе конента списка
            List<string> listContentTypeFieldNames = new List<string>();
            foreach (SPFieldLink listContentTypeFieldLink in listContentType.FieldLinks)
            {
                listContentTypeFieldNames.Add(listContentTypeFieldLink.Name);
            }

            // если первичное поле удаляется вместе с зависимыми, то необходимо отсортировать поля так,
            // чтобы сначала были удалены все зависимые поля, а только потом - первичное
            List<FieldDependancyInfo> fieldsToBeDeleted = new List<FieldDependancyInfo>();
            foreach (string listContentTypeFieldName in listContentTypeFieldNames)
            {
                if (applyFilter(listContentTypeFieldName))
                {
                    SPField listField = list.Fields.TryGetFieldByStaticName(listContentTypeFieldName);
                    if (listField != null)
                    {
                        if (!listField.Sealed && listField.Id != SPBuiltInFieldId.Title && (listField.AllowDeletion ?? true))
                        {
                            FieldDependancyInfo dependancyInfo = new FieldDependancyInfo();
                            dependancyInfo.Field = listField;
                            if (listField is SPFieldLookup)
                            {
                                dependancyInfo.IsDependent = ((SPFieldLookup)listField).IsDependentLookup;
                            }
                            fieldsToBeDeleted.Add(dependancyInfo);
                        }
                    }
                }
            }
            // поместим все зависимые поля в начало
            fieldsToBeDeleted = fieldsToBeDeleted.OrderBy(x => x, new FieldDependancyInfoComparer()).ToList();

            // удаляем поля
            foreach (FieldDependancyInfo fieldToBeDeleted in fieldsToBeDeleted)
            {
                // проверим, не используется ли поле в других типах контента
                int usageCount = 0;
                foreach (SPContentType ct in list.ContentTypes)
                {
                    if (ct.Fields.Contains(fieldToBeDeleted.Field.Id)) usageCount++;
                }

                try
                {
                    if (usageCount == 1) // поле используется только в типе контента, из которого его следует удалить
                    {
                        list.Fields.Delete(fieldToBeDeleted.Field.StaticName);
                        list.Update();
                        list = GetSPListFromFolderUrl(web, listFolderUrl); // переоткрываем список
                        listContentType = list.ContentTypes[listContentTypeId]; // переоткрываем тип контента
                    }
                    else // поле используется в нескольких типах контента
                    {
                        listContentType.FieldLinks.Delete(fieldToBeDeleted.Field.StaticName);
                        listContentType.Update();
                        listContentType = list.ContentTypes[listContentTypeId]; // переоткрываем тип контента
                    }
                }
                catch (Exception ex)
                {
                    string message = String.Format(
                        "Ошибка при удалении поля {0} из списка {1} по типу контента {2}",
                        fieldToBeDeleted.Field.StaticName,
                        list.Title,
                        listContentType.Name);
                    throw new Exception(message, ex);
                }
            }
        }
    }
}
